package imp

import (
	sqlc "bgs/db/sqlc"
	activityStatGrpc "bgs/grpc/gen/service/activity_stat"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"context"
	"database/sql"
	"fmt"
)

/****************************************************************************************/
/*                               activity_order_statAggs entity of helper                     */
/****************************************************************************************/

func transformActivityExposureStatEntityToPb(o sqlc.ActivityExposureStat) *activityStatGrpc.AggrActivityExposureStatEntity {
	return &activityStatGrpc.AggrActivityExposureStatEntity{
		Pv: uint32(o.Pv),
		Uv: uint32(o.Uv),
		Iv: uint32(o.Iv),
	}
}

func transformActivityOrderStatEntityToPb(o sqlc.ActivityOrderStat) *activityStatGrpc.AggrActivityOrderStatEntity {
	return &activityStatGrpc.AggrActivityOrderStatEntity{
		BuyerCount:               uint32(o.BuyerCount),
		OrderCount:               uint32(o.OrderCount),
		OrderAmount:              o.OrderAmount,
		DistributeAmount:         o.DistributeAmount,
		OrderBonus:               o.OrderBonus,
		Fee:                      o.Fee,
		WxpayCommission:          o.WxpayCommission,
		PlatformCommission:       o.PlatformCommission,
		RefundBuyerCount:         o.RefundBuyerCount,
		RefundOrderCount:         o.RefundOrderCount,
		RefundOrderAmount:        o.RefundOrderAmount,
		RefundDistributeAmount:   o.RefundDistributeAmount,
		RefundOrderBonus:         o.RefundOrderBonus,
		RefundFee:                o.RefundFee,
		RefundWxpayCommission:    o.RefundWxpayCommission,
		RefundPlatformCommission: o.RefundPlatformCommission,
	}
}

func transformAggrParentActivityExposureStatEntityToPb(o sqlc.AggrActivityExposureStatsByParentActivityIDRow) *activityStatGrpc.AggrActivityExposureStatEntity {
	return &activityStatGrpc.AggrActivityExposureStatEntity{
		Pv: uint32(o.Pv),
		Uv: uint32(o.Uv),
		Iv: uint32(o.Iv),
	}
}

func transformAggrParentActivityOrderStatEntityToPb(row sqlc.AggrActivityOrderStatsByParentActivityIDRow) *activityStatGrpc.AggrActivityOrderStatEntity {
	return &activityStatGrpc.AggrActivityOrderStatEntity{
		BuyerCount:               uint32(row.BuyerCount),
		OrderCount:               uint32(row.OrderCount),
		OrderAmount:              row.OrderAmount,
		DistributeAmount:         row.DistributeAmount,
		OrderBonus:               row.OrderBonus,
		Fee:                      row.Fee,
		WxpayCommission:          row.WxpayCommission,
		PlatformCommission:       row.PlatformCommission,
		RefundBuyerCount:         row.RefundBuyerCount,
		RefundOrderCount:         row.RefundOrderCount,
		RefundOrderAmount:        row.RefundOrderAmount,
		RefundDistributeAmount:   row.RefundDistributeAmount,
		RefundOrderBonus:         row.RefundOrderBonus,
		RefundFee:                row.RefundFee,
		RefundWxpayCommission:    row.RefundWxpayCommission,
		RefundPlatformCommission: row.RefundPlatformCommission,
	}
}

func transformRankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntityToPb(ptr *sqlc.RankActivityItemOfStoreWithStatsOverOrderAmountByStoreIDRow) *activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntity {
	return &activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntity{
		ActivityId:  ptr.ID,
		Name:        ptr.Name,
		OrderAmount: ptr.OrderAmount,
		OrderCount:  ptr.OrderCount,
	}
}

func mapRankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntityToPb(list []*sqlc.RankActivityItemOfStoreWithStatsOverOrderAmountByStoreIDRow, f func(*sqlc.RankActivityItemOfStoreWithStatsOverOrderAmountByStoreIDRow) *activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntity) []*activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntity {
	r := make([]*activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               activity_order_statAggs entity of query                */
/****************************************************************************************/

// AggrActivityOrderStatsOfBrandByActivityID  统计品牌的活动订单情况
func (s *ActivityAPIService) AggrActivityStatsOfBrandByActivityID(ctx context.Context, req *activityStatGrpc.AggrActivityStatsOfBrandByActivityIDRequest) (res *activityStatGrpc.AggrActivityStatsOfBrandByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->AggrActivityStatsOfBrandByActivityID:%v", req)

	res = &activityStatGrpc.AggrActivityStatsOfBrandByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	activityID := req.ActivityId
	activity, err := q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if activity.BrandID != req.BrandId {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     "品牌不匹配",
		}
		return
	}

	aggrExposureOfOwn, err := s.activityService.EnsureActivityExposureStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	activityOrderStat, err := s.activityService.EnsureActivityOrderStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	aggrExposureOfEndorsement, err := s.activityService.AggrActivityExposureStatsByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	aggrOrderOfEndorsement, err := s.activityService.AggrActivityOrderStatsByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.AggrExposureOfOwn = transformActivityExposureStatEntityToPb(aggrExposureOfOwn)
	res.AggrOrderOfOwn = transformActivityOrderStatEntityToPb(activityOrderStat)
	res.AggrExposureOfEndorsement = transformAggrParentActivityExposureStatEntityToPb(aggrExposureOfEndorsement)
	res.AggrOrderOfEndorsement = transformAggrParentActivityOrderStatEntityToPb(aggrOrderOfEndorsement)
	return
}

// AggrActivityStatsOfStoreByActivityID  统计门店的活动订单情况
func (s *ActivityAPIService) AggrActivityStatsOfStoreByActivityID(ctx context.Context, req *activityStatGrpc.AggrActivityStatsOfStoreByActivityIDRequest) (res *activityStatGrpc.AggrActivityStatsOfStoreByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->AggrActivityStatsOfStoreByActivityID:%v", req)

	res = &activityStatGrpc.AggrActivityStatsOfStoreByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	activityID := req.ActivityId
	activity, err := q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if !activity.StoreID.Valid || activity.StoreID.Int64 != req.StoreId {
		err = fmt.Errorf("活动不是门店发布")
		return
	}

	aggrExposureOfOwn, err := s.activityService.EnsureActivityExposureStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	activityOrderStat, err := s.activityService.EnsureActivityOrderStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	aggrExposureOfEndorsement, err := s.activityService.AggrActivityExposureStatsByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	aggrOrderOfEndorsement, err := s.activityService.AggrActivityOrderStatsByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.AggrExposureOfOwn = transformActivityExposureStatEntityToPb(aggrExposureOfOwn)
	res.AggrOrderOfOwn = transformActivityOrderStatEntityToPb(activityOrderStat)
	res.AggrExposureOfEndorsement = transformAggrParentActivityExposureStatEntityToPb(aggrExposureOfEndorsement)
	res.AggrOrderOfEndorsement = transformAggrParentActivityOrderStatEntityToPb(aggrOrderOfEndorsement)
	return
}

// AggrActivityStatsOfSpokesmanByActivityID  统计代言人的活动情况
func (s *ActivityAPIService) AggrActivityStatsOfSpokesmanByActivityID(ctx context.Context, req *activityStatGrpc.AggrActivityStatsOfSpokesmanByActivityIDRequest) (res *activityStatGrpc.AggrActivityStatsOfSpokesmanByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->AggrActivityStatsOfSpokesmanByActivityID:%v", req)

	res = &activityStatGrpc.AggrActivityStatsOfSpokesmanByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activityID := req.ActivityId
	activity, err := q.GetActivity(ctx, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if activity.SpokesmanID.Int64 != req.SpokesmanId {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     "代言人不匹配",
		}
		return
	}

	activityExposureStat, err := s.activityService.EnsureActivityExposureStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	activityOrderStat, err := s.activityService.EnsureActivityOrderStat(ctx, q, false, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.AggrExposureOfEndorsement = transformActivityExposureStatEntityToPb(activityExposureStat)
	res.AggrOrderOfEndorsement = transformActivityOrderStatEntityToPb(activityOrderStat)
	return
}

// RankActivityItemOfStoreForDistributorWithStatsOverOrderAmount 分销员门店活动的销售金额排名
func (s *ActivityAPIService) RankActivityItemOfStoreForDistributorWithStatsOverOrderAmount(ctx context.Context, req *activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountRequest) (res *activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->RankActivityItemOfStoreForDistributorWithStatsOverOrderAmount:%v", req)
	res = &activityStatGrpc.RankActivityItemOfStoreForDistributorWithStatsOverOrderAmountResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	distributorID := req.DistributorId
	storePtr, err := s.storeService.GetStorePtrByDistributorID(ctx, q, distributorID)
	if err != nil {
		if sql.ErrNoRows == err {
			// 分销员没有开通门店,产品说不用报错
			err = nil
			return
		}
		return
	}
	total, ptrs, err := s.activityService.RankActivityItemOfStoreWithStatsOverOrderAmount(ctx, q, &util.Pager{
		Ts:     ts,
		Limit:  req.Limit,
		Offset: req.Offset,
	}, storePtr.ID)
	if err != nil {
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	res.Total = total
	res.ActivityItemOfStoreForDistributorWithStats = mapRankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntityToPb(ptrs, transformRankActivityItemOfStoreForDistributorWithStatsOverOrderAmountEntityToPb)
	return
}

/****************************************************************************************/
/*                               activity_user_order_statAggs entity of helper          */
/****************************************************************************************/

func transformAggrOfActivityConsignmentEntityToPb(spokesmanCount int64, consignmentAmount int64) *activityStatGrpc.AggrActivityConsignmentEntity {
	return &activityStatGrpc.AggrActivityConsignmentEntity{
		SpokesmanCount:    uint32(spokesmanCount),
		ConsignmentAmount: consignmentAmount,
	}
}

func transformAggrOfActivityConsignmentForSpokesmanEntityToPb(o sqlc.AggrActivityUserOrderStatsForSpokesmanByParentActivityIDRow) *activityStatGrpc.AggrActivityConsignmentForSpokesmanEntity {
	return &activityStatGrpc.AggrActivityConsignmentForSpokesmanEntity{
		OrderCount:            uint32(o.OrderCount),
		OrderAmount:           o.OrderAmount,
		OrderBonus:            o.OrderBonus,
		SpokesmanId:           o.SpokesmanID.Int64,
		SpokesmanUserId:       o.SpokesmanUserID.Int64,
		Published:             sqlc.GoNTimeToPBTimestamp(o.Published),
		SpokesmanUserNickName: o.SpokesmanUserNickName.String,
		SpokesmanUserPic:      o.SpokesmanUserPic.String,
		SpokesmanUserMobile:   o.SpokesmanUserMobile.String,
	}
}

func mapAggrOfActivityConsignmentForSpokesmanEntityToPb(list []sqlc.AggrActivityUserOrderStatsForSpokesmanByParentActivityIDRow, f func(sqlc.AggrActivityUserOrderStatsForSpokesmanByParentActivityIDRow) *activityStatGrpc.AggrActivityConsignmentForSpokesmanEntity) []*activityStatGrpc.AggrActivityConsignmentForSpokesmanEntity {
	r := make([]*activityStatGrpc.AggrActivityConsignmentForSpokesmanEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformRankOverOrderAmountForSpokesmanEntityToPb(o sqlc.RankActivityUserOrderStatsOverOrderAmountForSpokesmanByParentActivityIDRow) *activityStatGrpc.RankOverOrderAmountForSpokesmanEntity {
	return &activityStatGrpc.RankOverOrderAmountForSpokesmanEntity{
		OrderAmount:           o.OrderAmount,
		RefundOrderAmount:     o.RefundOrderAmount,
		OrderBonus:            o.OrderBonus,
		OrderAmountRank:       uint32(o.OrderAmountRank),
		SpokesmanId:           o.SpokesmanID.Int64,
		SpokesmanUserId:       o.SpokesmanUserID.Int64,
		SpokesmanUserNickName: o.SpokesmanUserNickName.String,
	}
}

func mapRankOverOrderAmountForSpokesmanEntityToPb(list []sqlc.RankActivityUserOrderStatsOverOrderAmountForSpokesmanByParentActivityIDRow, f func(sqlc.RankActivityUserOrderStatsOverOrderAmountForSpokesmanByParentActivityIDRow) *activityStatGrpc.RankOverOrderAmountForSpokesmanEntity) []*activityStatGrpc.RankOverOrderAmountForSpokesmanEntity {
	r := make([]*activityStatGrpc.RankOverOrderAmountForSpokesmanEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               activity_user_order_statAggs entity of query           */
/****************************************************************************************/

// AggrConsignmentByActivityID  统计活动帮卖信息
func (s *ActivityAPIService) AggrConsignmentByActivityID(ctx context.Context, req *activityStatGrpc.AggrConsignmentByActivityIDRequest) (res *activityStatGrpc.AggrConsignmentByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->AggrConsignmentByActivityID:%v", req)

	res = &activityStatGrpc.AggrConsignmentByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activityID := req.ActivityId
	spokesmanCount, err := q.CountSpokesmanOwnActivitiesByParentActivityID(ctx, sqlc.NInt64FromInt64(activityID))
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	consignmentAmount, err := s.activityService.AggrActivityUserOrderStatsForOrderAmoumntByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.AggrActivityConsignment = transformAggrOfActivityConsignmentEntityToPb(spokesmanCount, consignmentAmount)
	return
}

// AggrConsignmentForSpokesmanByActivityID  统计各代言人的帮卖信息
func (s *ActivityAPIService) AggrConsignmentForSpokesmanByActivityID(ctx context.Context, req *activityStatGrpc.AggrConsignmentForSpokesmanByActivityIDRequest) (res *activityStatGrpc.AggrConsignmentForSpokesmanByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->AggrConsignmentForSpokesmanByActivityID:%v", req)

	res = &activityStatGrpc.AggrConsignmentForSpokesmanByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activityID := req.ActivityId

	aggrRet, err := s.activityService.AggrActivityUserOrderStatsForSpokesmanByParentActivityID(ctx, q, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.AggrActivityConsignmentForSpokesman = mapAggrOfActivityConsignmentForSpokesmanEntityToPb(aggrRet, transformAggrOfActivityConsignmentForSpokesmanEntityToPb)
	return
}

// RankOverOrderAmountForSpokesmanByActivityID  排名各代言人的销售额
func (s *ActivityAPIService) RankOverOrderAmountForSpokesmanByActivityID(ctx context.Context, req *activityStatGrpc.RankOverOrderAmountForSpokesmanByActivityIDRequest) (res *activityStatGrpc.RankOverOrderAmountForSpokesmanByActivityIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_statImp->RankOverOrderAmountForSpokesmanByActivityID:%v", req)

	res = &activityStatGrpc.RankOverOrderAmountForSpokesmanByActivityIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	activityID := req.ActivityId

	aggrRet, err := s.activityService.RankActivityUserOrderStatsOverOrderAmountForSpokesmanByParentActivityID(ctx, q, req.TopRankNumber, activityID)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.RankOverOrderAmountForSpokesmans = mapRankOverOrderAmountForSpokesmanEntityToPb(aggrRet, transformRankOverOrderAmountForSpokesmanEntityToPb)
	return
}
